package com.algorithm.snowflake;

/**
 * 功能描述
 *
 * @author fujc-dev@qq.com
 * @date: 2023年08月24日 9:07
 */

public class SnowflakeIDGenerator {

    // 设置起始时间戳，这里是2021-09-01 00:00:00
    private static final long EPOCH = 1630368000000L;
    // 序列号占用的位数
    private static final long SEQUENCE_BITS = 4;
    // 工作机器ID占用的位数
    private static final long WORKER_ID_BITS = 4;
    // 工作机器ID的最大值
    private static final long MAX_WORKER_ID = (1L << WORKER_ID_BITS) - 1;
    // 序列号的最大值
    private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
    // 当前工作机器ID
    private final long workerId;
    // 当前序列号
    private long sequence = 0L;
    // 上次生成ID的时间戳
    private long lastTimestamp = -1L;

    public SnowflakeIDGenerator(long workerId) {
        if (workerId < 0 || workerId > MAX_WORKER_ID) {
            throw new IllegalArgumentException("Worker ID must be between 0 and " + MAX_WORKER_ID);
        }
        // 初始化工作机器ID
        this.workerId = workerId;
    }

    public synchronized long generateID() {
        // 获取当前时间戳
        long currentTimestamp = System.currentTimeMillis();

        // 检查时钟回拨
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID for " + (lastTimestamp - currentTimestamp) + " milliseconds.");
        }
        // 同一毫秒内生成多个ID
        if (currentTimestamp == lastTimestamp) {
            // 增加序列号
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                // 序列号用尽，等待下一毫秒
                currentTimestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            // 不同毫秒，序列号重置
            sequence = 0L;
        }
        // 更新上次生成ID的时间戳
        lastTimestamp = currentTimestamp;
        // 组合各部分生成最终的ID
        return ((currentTimestamp - EPOCH) << (WORKER_ID_BITS + SEQUENCE_BITS))
            | (workerId << SEQUENCE_BITS)
            | sequence;
    }

    private long waitNextMillis(long lastTimestamp) {
        long currentTimestamp = System.currentTimeMillis();
        // 等待直到下一毫秒
        while (currentTimestamp <= lastTimestamp) {
            currentTimestamp = System.currentTimeMillis();
        }
        return currentTimestamp;
    }

    public static void main(String[] args) {
        SnowflakeIDGenerator idGenerator = new SnowflakeIDGenerator(1);

        for (int i = 0; i < 10; i++) {
            // 生成ID
            long id = idGenerator.generateID();
            System.out.println("Generated ID: " + id);
        }
    }
}
